from drf_spectacular.utils import OpenApiTypes, extend_schema_field
from rest_framework import serializers

from sysreptor.pentests.models import LockInfo
from sysreptor.pentests.rendering.error_messages import MessageLevel, MessageLocationType
from sysreptor.users.serializers import PentestUserSerializer, RelatedUserSerializer


class LockInfoSerializer(serializers.ModelSerializer):
    user = PentestUserSerializer(read_only=True)

    def __init__(self, *args, **kwargs):
        kwargs['read_only'] = True
        super().__init__(*args, **kwargs)

    class Meta:
        model = LockInfo
        fields = [
            'created', 'updated', 'last_ping', 'expires', 'user',
        ]
        read_only_fields = ['last_ping']


class ImportSerializer(serializers.Serializer):
    file = serializers.FileField(write_only=True)

    id = serializers.UUIDField(read_only=True)


class CopySerializer(serializers.Serializer):
    id = serializers.UUIDField(read_only=True)

    def update(self, instance, validated_data):
        return instance.copy()


class EnumChoiceField(serializers.ChoiceField):
    def __init__(self, choices, **kwargs):
        self.choices_enum = choices
        super().__init__(choices=list(map(lambda e: e.value, self.choices_enum)), **kwargs)

    def to_internal_value(self, data):
        return self.choices_enum(super().to_internal_value(data))

    def to_representation(self, value):
        if isinstance(value, self.choices_enum):
            value = value.value
        return super().to_representation(value)


class MessageLocationSerializer(serializers.Serializer):
    type = EnumChoiceField(choices=MessageLocationType)
    id = serializers.CharField(allow_null=True)
    name = serializers.CharField(allow_null=True)
    path = serializers.CharField(allow_null=True)


class ErrorMessageSerializer(serializers.Serializer):
    level = EnumChoiceField(choices=MessageLevel)
    message = serializers.CharField()
    details = serializers.CharField(allow_null=True)
    location = MessageLocationSerializer()


class LockableObjectSerializer(serializers.Serializer):
    id = serializers.UUIDField(read_only=True)
    lock_info = LockInfoSerializer(read_only=True)


class ExportSerializer(serializers.Serializer):
    pass


class PdfResponseSerializer(serializers.Serializer):
    pdf = extend_schema_field(OpenApiTypes.BYTE)(serializers.CharField(allow_null=True, read_only=True))
    messages = ErrorMessageSerializer(many=True, read_only=True)
    timings = serializers.DictField(child=serializers.FloatField(min_value=0), read_only=True)


class HistoryTimelineSerializer(serializers.Serializer):
    history_date = serializers.DateTimeField()
    history_type = serializers.CharField()
    history_change_reason = serializers.CharField(allow_null=True)
    history_title = serializers.CharField(allow_null=True)
    history_user = RelatedUserSerializer(allow_null=True)
    history_model = serializers.CharField()
    id = serializers.CharField(source='model_id')


class TagsSerializer(serializers.Serializer):
    tags = serializers.ListField(child=serializers.CharField())

